<!doctype html><html class="use-motion" lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="google-site-verification" content="0axhmy0-lA3xPbR8wPgyWlMZjwWSCfagKukdyeCQ7LU"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css"><meta name="keywords" content="EMC,dpcls,megaflow,OVS,SDN,OpenvSwitch,Network"><link rel="alternate" href="/atom.xml" title="赵占旭的博客" type="application/atom+xml"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0"><meta name="description" content="推荐看一下这篇文章，讲述了各个流表，我们这里着重讲流程和代码，对流表不再细说。"><meta name="keywords" content="EMC,dpcls,megaflow,OVS,SDN,OpenvSwitch,Network"><meta property="og:type" content="article"><meta property="og:title" content="OpenvSwitch 流表转换"><meta property="og:url" content="http://zhaozhanxu.com/2017/03/05/SDN/OVS/2017-03-05-flow-translate/index.html"><meta property="og:site_name" content="赵占旭的博客"><meta property="og:description" content="推荐看一下这篇文章，讲述了各个流表，我们这里着重讲流程和代码，对流表不再细说。"><meta property="og:locale" content="en"><meta property="og:updated_time" content="2017-12-11T14:31:18.941Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="OpenvSwitch 流表转换"><meta name="twitter:description" content="推荐看一下这篇文章，讲述了各个流表，我们这里着重讲流程和代码，对流表不再细说。"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",sidebar:{position:"left",display:"post",offset:342,offset_float:0},fancybox:!0,motion:!0}</script><link rel="canonical" href="http://zhaozhanxu.com/2017/03/05/SDN/OVS/2017-03-05-flow-translate/"><title> OpenvSwitch 流表转换 | 赵占旭的博客</title></head><body itemscope itemtype="http://schema.org/WebPage" lang="en"><script>!function(e,a,t,c,n,g,o){e.GoogleAnalyticsObject="ga",e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,g=a.createElement("script"),o=a.getElementsByTagName("script")[0],g.async=1,g.src="//www.google-analytics.com/analytics.js",o.parentNode.insertBefore(g,o)}(window,document),ga("create","3a235f2280210fdd34cebc8c3647e5b8","auto"),ga("send","pageview")</script><script type="text/javascript">var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?UA-90327054-1";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><script type="text/javascript">!function(){var e=document.createElement("script");e.src="//tajs.qq.com/stats?sId=60806179";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><div class="container one-collumn sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader" style="background-image:url(/images/public/home_bg.jpg)"><div class="header-cover"><div class="header-inner"><a class="site-home" href="/">赵占旭的博客</a><div class="site-meta"><div class="custom-logo-site-title"><div href="/" class="brand"><span class="logo-line-before"><i></i></span> <span class="site-title">赵占旭的博客</span><span class="logo-line-after"><i></i></span></div></div><h1 class="site-subtitle" itemprop="description">一花一世界 一叶一菩提</h1></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-categories"><a href="/categories" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> Categories</a></li><li class="menu-item menu-item-tags"><a href="/tags" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> Tags</a></li><li class="menu-item menu-item-archives"><a href="/archives" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> Archives</a></li><li class="menu-item menu-item-about"><a href="/about" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i><br> About</a></li><li class="menu-item menu-item-search"><a href="javascript:" ; class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> Search</a></li></ul><div class="site-search"><div class="popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocapitalize="off" autocomplete="off" autocorrect="off" placeholder="search.placeholder" spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div><div class="header-post"><div class="post-header"><div class="tags"> <a href="/tags/OVS/" rel="tag" title="OVS">OVS</a> <a href="/tags/Network/" rel="tag" title="Network">Network</a> <a href="/tags/SDN/" rel="tag" title="SDN">SDN</a></div><h1>OpenvSwitch 流表转换</h1><h2 class="subtitle">OVS Userspace流表翻译为Datapath流表</h2><div class="post-time"> <span class="post-meta-item-text">Posted on</span> <time itemprop="dateCreated" datetime="2017-03-05T00:00:00+08:00" content="2017-03-05" title="2017-03-05 00:00:00">2017-03-05</time></div></div></div></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><link itemprop="mainEntityOfPage" href="http://zhaozhanxu.com/2017/03/05/SDN/OVS/2017-03-05-flow-translate/"><span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="赵占旭"><meta itemprop="description" content=""><meta itemprop="image" content="/images/public/me.jpg"></span><span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="赵占旭的博客"> <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject"><img style="display:none" itemprop="url image" alt="赵占旭的博客" src=""></span></span><div class="post-inner"><header class="post-header"><h2 class="post-title" itemprop="name headline"> OpenvSwitch 流表转换</h2><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">Posted on</span> <time title="Post created" itemprop="dateCreated datePublished" datetime="2017-03-05T00:00:00+08:00">2017-03-05</time></span></div></header><div class="post-info"><div class="post-categories"> <a class="color" href="/categories/OVS/" rel="tag">OVS</a></div><div class="post-tags"> <a class="color" href="/tags/OVS/" rel="tag">OVS</a> <a class="color" href="/tags/Network/" rel="tag">Network</a> <a class="color" href="/tags/SDN/" rel="tag">SDN</a></div><div class="clearfix"></div></div><div class="post-body" itemprop="articleBody"><p>推荐看一下这篇<a href="/2016/12/16/SDN/OVS/2016-12-16-datapath-classifier/">文章</a>，讲述了各个流表，我们这里着重讲流程和代码，对流表不再细说。</p><a id="more"></a><p>我们主要的关注点还是OVS-DPDK的流表转换，其实和OVS的转换差不多，只不过OVS的Datapath流表位于kernel，报文在Datapath找不到流表即通过netlink上传到Userspace，而OVS-DPDK则是Datapath流表依然位于Userspace，可以看做是一个缓存。查找不到的话直接继续调用其他接口查找Userspace的流表。</p><h1 id="主要流程"><a href="#主要流程" class="headerlink" title="主要流程"></a>主要流程</h1><hr><ul><li>controller会根据网络情况给ovs下发流表，或者命令ovs-ofctl，属于Userspace的流表(ofproto classifier)。</li><li>当报文来的时候会先提取key值，然后在Datapath的流表(EMC或者microflow)进行查找匹配，查找到之后会进行action操作</li><li>如果没有查找到，就会转而继续查找Datapath的流表(也叫dpcls、TSS classifier、megaflow)。</li><li>dpcls有好多的子表，根据掩码来分类，需要挨个查找每个子表，如果查找到就会讲带掩码的流表转换成精确匹配的流表，然后匹配转发</li><li>如果匹配不到就会将key和报文传递给Userspace进行匹配</li><li>Userspace的查找会根据优先级和对每个table进行查找，然后执行相应的操作，最后匹配的所有流表会进行组合生成更简单的一些流表，比如table 0有n0条流表，一直到table 24有n24条流表，那么最终生成的dpcls流表可能有n1 x n2 x … x n24中可能性</li><li>将生成的流表转换安装到dpcls，然后转换安装到EMC</li><li>如果匹配不到的话会丢弃或者上报packet in给controller</li></ul><h1 id="边界点"><a href="#边界点" class="headerlink" title="边界点"></a>边界点</h1><hr><ul><li>EMC是以pmd为边界的，每个pmd都有自己的一套EMC</li><li>dpcls是以端口边界的，每个端口都有自己的dpcls流表</li><li>ofproto classifier是以桥为边界的，每个桥都有自己的流表</li></ul><h1 id="流表下发"><a href="#流表下发" class="headerlink" title="流表下发"></a>流表下发</h1><hr><p>其实前面我们说到了三种存在形式的流表，这里流表下发只是下到了ofproto classifier了，其他的都是需要报文去触发去上一级拉取相应的流表。</p><h2 id="流表发送"><a href="#流表发送" class="headerlink" title="流表发送"></a>流表发送</h2><p>流表下发一般是两种方式:</p><ul><li>controller，根据情况生成流表，通过openflow协议下发flow mod给ovs的Userspace流表。</li><li>命令ovs-ofctl，这个是根据命令情况生成流表，通过openflow协议下发flow mod给ovs的Userspace流表。</li></ul><p>流表下发我们就先不去看了，因为我目前的原则是操作命令先不看，先看服务，controller后面会看ovn的，到时候单独来写。</p><h2 id="流表接收"><a href="#流表接收" class="headerlink" title="流表接收"></a>流表接收</h2><p>流表接收是指将命令行或者controller下发的流表接收，并且暂存。</p><h3 id="服务启动"><a href="#服务启动" class="headerlink" title="服务启动"></a>服务启动</h3><p><code>ovs-vswitchd.c</code>的路径为<code>main--&gt;bridge_run--&gt;bridge_run__(针对每个桥运行ofproto)--&gt;ofproto_run(信息量大，暂时忽略)--&gt;handle_openflow</code></p><h4 id="handle-openflow-gt-handle-openflow"><a href="#handle-openflow-gt-handle-openflow" class="headerlink" title="handle_openflow--&gt;handle_openflow__"></a><code>handle_openflow--&gt;handle_openflow__</code></h4><ul><li>提取openflow协议的类型</li><li>简单介绍下部分openflow的协议类型<ul><li>ECHO是握手</li><li>FEATURES是同步版本和特性</li><li>CONFIG是同步配置</li><li>PACKET_OUT发包</li><li>PORT_MOD修改端口信息</li><li><strong>FLOW_MOD修改流表，这个是最关键的</strong></li><li>GROUP_MOD, TABLE_MOD, METER_MOD</li></ul></li><li>最重要的<code>OFPTYPE_FLOW_MOD</code>的操作为<code>handle_flow_mod</code>主要是对流表的操作</li></ul><h4 id="handle-flow-mod"><a href="#handle-flow-mod" class="headerlink" title="handle_flow_mod"></a><code>handle_flow_mod</code></h4><ul><li><code>ofputil_decode_flow_mod</code>主要是将FLOW_MOD信息解析到<code>ofputil_flow_mod</code>结构中</li><li><code>handle_flow_mod__--&gt;ofproto_flow_mod_init</code>主要是将上面<code>ofputil_flow_mod</code>结构的数据解析到结构<code>ofproto_flow_mod</code>中。</li><li><code>handle_flow_mod__--&gt;ofproto_flow_mod_start</code>支持了流表添加、删除、修改的操作，我们主要关注添加，即<code>add_flow_start</code></li></ul><h4 id="ofproto-flow-mod-init"><a href="#ofproto-flow-mod-init" class="headerlink" title="ofproto_flow_mod_init"></a><code>ofproto_flow_mod_init</code></h4><p><code>ofproto_flow_mod_init</code>涉及到数据结构的转换，我们先看下两个数据结构，然后看一下怎么转换的</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ofputil_flow_mod</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ovs_list</span> <span class="title">list_node</span>;</span> <span class="comment">/* For queuing flow_mods. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//匹配项，支持standard和OXM两种类型</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">match</span> <span class="title">match</span>;</span></span><br><span class="line">    <span class="comment">//流表优先级</span></span><br><span class="line">    <span class="keyword">int</span> priority;</span><br><span class="line">    <span class="comment">//添加流表时这两项为0</span></span><br><span class="line">    ovs_be64 cookie;         <span class="comment">/* Cookie bits to match. */</span></span><br><span class="line">    ovs_be64 cookie_mask;    <span class="comment">/* 1-bit in each 'cookie' bit to match. */</span></span><br><span class="line">    ovs_be64 new_cookie;     <span class="comment">/* New cookie to install or UINT64_MAX. */</span></span><br><span class="line">    <span class="keyword">bool</span> modify_cookie;      <span class="comment">/* Set cookie of existing flow to 'new_cookie'? */</span></span><br><span class="line">    <span class="comment">//流表的table id，只有删除的时候不需要指定</span></span><br><span class="line">    <span class="keyword">uint8_t</span> table_id;</span><br><span class="line">    <span class="comment">//操作命令，是添加、删除还是修改</span></span><br><span class="line">    <span class="keyword">uint16_t</span> command;</span><br><span class="line">    <span class="comment">//空闲超时时间，即流表没有报文之后多长时间销毁流表</span></span><br><span class="line">    <span class="keyword">uint16_t</span> idle_timeout;</span><br><span class="line">    <span class="comment">//硬超时时间，从建立起多长时间销毁流表，不论有木有报文</span></span><br><span class="line">    <span class="keyword">uint16_t</span> hard_timeout;</span><br><span class="line">    <span class="keyword">uint32_t</span> buffer_id;</span><br><span class="line">    <span class="comment">//出端口</span></span><br><span class="line">    <span class="keyword">ofp_port_t</span> out_port;</span><br><span class="line">    <span class="keyword">uint32_t</span> out_group;</span><br><span class="line">    <span class="comment">//一些操作标识，比如要不要统计等等</span></span><br><span class="line">    <span class="keyword">enum</span> ofputil_flow_mod_flags flags;</span><br><span class="line">    <span class="keyword">uint16_t</span> importance;     <span class="comment">/* Eviction precedence. */</span></span><br><span class="line">    <span class="comment">//操作</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ofpact</span> *<span class="title">ofpacts</span>;</span>  <span class="comment">/* Series of "struct ofpact"s. */</span></span><br><span class="line">    <span class="keyword">size_t</span> ofpacts_len;      <span class="comment">/* Length of ofpacts, in bytes. */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>将<code>ofputil_flow_mod</code>的数据转换为<code>ofproto_flow_mod</code>的数据</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ofproto_flow_mod</span> &#123;</span></span><br><span class="line">    <span class="comment">//rculist链表，里面存储了match项，和上面的match项还是有差别的</span></span><br><span class="line">    <span class="comment">//上面的match结构主要是flow和mask两个结构</span></span><br><span class="line">    <span class="comment">//rule里面的是minimatch，里面包含了上面的两个flow，并且还有flowmap</span></span><br><span class="line">    <span class="comment">//rule的其他信息基本上是从上面拷贝过来的</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rule</span> *<span class="title">temp_rule</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rule_criteria</span> <span class="title">criteria</span>;</span></span><br><span class="line">    <span class="comment">//和actions相关的，不太明白</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">cls_conjunction</span> *<span class="title">conjs</span>;</span></span><br><span class="line">    <span class="keyword">size_t</span> n_conjs;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//以下两条直接从上面数据结构拷贝</span></span><br><span class="line">    <span class="keyword">uint16_t</span> command;</span><br><span class="line">    <span class="keyword">bool</span> modify_cookie;</span><br><span class="line">    <span class="comment">//允许添加流表</span></span><br><span class="line">    <span class="keyword">bool</span> modify_may_add_flow;</span><br><span class="line">    <span class="comment">//取自上面的flags，是否保持统计，false表示重新统计</span></span><br><span class="line">    <span class="keyword">bool</span> modify_keep_counts;</span><br><span class="line">    <span class="keyword">enum</span> nx_flow_update_event event;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">ovs_version_t</span> version;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">bool</span> learn_adds_rule;               <span class="comment">/* Learn execution adds a rule. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rule_collection</span> <span class="title">old_rules</span>;</span>   <span class="comment">/* Affected rules. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rule_collection</span> <span class="title">new_rules</span>;</span>   <span class="comment">/* Replacement rules. */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li>首先直接拷贝过来的结构包括command、modify_cookie</li><li>然后根据操作的命令执行不同的函数，我先关注添加，即调用<code>add_flow_init</code><ul><li>没有指定table_id则指定table_id为0</li><li>根据指定的table_id找到数据结构oftable</li><li>调用<code>cls_rule_init</code>和<code>ofproto_rule_create</code>创建<code>ofm-&gt;temp_rule</code>，这个接下来详细说下，主要是priority和match的填充</li><li>调用<code>get_conjunctions</code>获取根据上面的ofpacts填充下面的conjs，这块还是不太懂，是和action相关的信息</li></ul></li></ul><h5 id="rule创建"><a href="#rule创建" class="headerlink" title="rule创建"></a><code>rule创建</code></h5><p>要看rule创建，我们首先了解一下rule的数据结构，然后看一下当前填充的priority和match</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rule</span> &#123;</span></span><br><span class="line">    <span class="comment">//包含自己的ofproto</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ofproto</span> *<span class="title">const</span> <span class="title">ofproto</span>;</span> <span class="comment">/* The ofproto that contains this rule. */</span></span><br><span class="line">    <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">cls_rule</span> <span class="title">cr</span>;</span>      <span class="comment">/* In owning ofproto's classifier. */</span></span><br><span class="line">    <span class="comment">//流表中看到的table_id</span></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">uint8_t</span> table_id;        <span class="comment">/* Index in ofproto's 'tables' array. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//流表状态，包括初始化、插入和删除</span></span><br><span class="line">    <span class="keyword">enum</span> rule_state state;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//用于释放的引用计数</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ovs_refcount</span> <span class="title">ref_count</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> ovs_be64 flow_cookie; <span class="comment">/* Immutable once rule is constructed. */</span></span><br><span class="line">    <span class="function">struct hindex_node cookie_node <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">enum</span> ofputil_flow_mod_flags flags OVS_GUARDED;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//对应上面的两个超时</span></span><br><span class="line">    <span class="keyword">uint16_t</span> hard_timeout OVS_GUARDED; <span class="comment">/* In seconds from -&gt;modified. */</span></span><br><span class="line">    <span class="keyword">uint16_t</span> idle_timeout OVS_GUARDED; <span class="comment">/* In seconds from -&gt;used. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Eviction precedence. */</span></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">uint16_t</span> importance;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">uint8_t</span> removed_reason;</span><br><span class="line"></span><br><span class="line">    <span class="function">struct eviction_group *eviction_group <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line">    <span class="function">struct heap_node evg_node <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//action操作</span></span><br><span class="line">    <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rule_actions</span> * <span class="title">const</span> <span class="title">actions</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* In owning meter's 'rules' list.  An empty list if there is no meter. */</span></span><br><span class="line">    <span class="function">struct ovs_list meter_list_node <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">enum</span> nx_flow_monitor_flags monitor_flags <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line">    <span class="keyword">uint64_t</span> <span class="function">add_seqno <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line">    <span class="keyword">uint64_t</span> <span class="function">modify_seqno <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function">struct ovs_list expirable <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> created OVS_GUARDED; <span class="comment">/* Creation time. */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> modified OVS_GUARDED; <span class="comment">/* Time of last modification. */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h6 id="cls-rule-init"><a href="#cls-rule-init" class="headerlink" title="cls_rule_init"></a><code>cls_rule_init</code></h6><p>该函数主要是填充的ofm-&gt;temp_rule-&gt;cr</p><ul><li><code>cls_rule_init__</code>是将priority填充</li><li><code>minimatch_init</code>主要是将match填充，主要将struct match中的flow和wc分别填充到struct minimatch的flow和mask</li></ul><h6 id="ofproto-rule-create"><a href="#ofproto-rule-create" class="headerlink" title="ofproto_rule_create"></a><code>ofproto_rule_create</code></h6><p>该函数主要是创建ofm-&gt;temp_rule，并且填充一系列的内容，包括上面的new_cookie、idle_timeout、hard_timeout、flags、importance、ofpacts等</p><ul><li><code>ofproto-&gt;ofproto_class-&gt;rule_alloc</code>申请rule空间</li><li>rule-&gt;ofproto = ofproto指向自己的father</li><li>初始化引用计数ref_count</li><li>复制过来new_cookie、idle_timeout、hard_timeout、flags、importance</li><li>记录创建时间</li><li>调用<code>rule_actions_create</code>来填充之前的ofpacts信息</li><li>调用<code>rule_construct</code>进行一些信息的初始化</li></ul><h4 id="add-flow-start"><a href="#add-flow-start" class="headerlink" title="add_flow_start"></a><code>add_flow_start</code></h4><ul><li><code>classifier_find_rule_exactly</code>从流表指定的table(table_id)的classifier中通过掩码找到子表，在子表中进行匹配，必须找到匹配项，并且优先级和rule版本匹配，则找到流表，否则都是不匹配返回NULL</li><li>没有匹配到规则，则需要判定规则总数是否超过最大值(UINT_MAX)，超过需要删除一条流表。实际操作就是用新的流表替换掉旧的流表</li><li>如果找到匹配的规则，说明已有规则，则需要用新的流表替换掉旧的流表</li><li><code>replace_rule_start</code>主要操作就是新的流表替换旧的流表的操作，如果存在旧流表，则调用<code>ofproto_rule_remove__</code>删除，然后调用<code>ofproto_rule_insert__</code>和<code>classifier_insert</code>添加流表。其中<code>classifier_insert</code>主要是将rule-&gt;cr添加到table-&gt;cls中</li></ul><h4 id="ofproto-rule-insert"><a href="#ofproto-rule-insert" class="headerlink" title="ofproto_rule_insert__"></a><code>ofproto_rule_insert__</code></h4><p>该函数主要是将rule插入到ofproto中去，上面有了rule的数据结构，下面我们看一下ofproto数据结构存储了什么信息</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ofproto</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hmap_node</span> <span class="title">hmap_node</span>;</span> <span class="comment">/* In global 'all_ofprotos' hmap. */</span></span><br><span class="line">    <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ofproto_class</span> *<span class="title">ofproto_class</span>;</span></span><br><span class="line">    <span class="keyword">char</span> *type;                 <span class="comment">/* Datapath type. */</span></span><br><span class="line">    <span class="keyword">char</span> *name;                 <span class="comment">/* Datapath name. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Settings. */</span></span><br><span class="line">    <span class="keyword">uint64_t</span> fallback_dpid;     <span class="comment">/* Datapath ID if no better choice found. */</span></span><br><span class="line">    <span class="keyword">uint64_t</span> datapath_id;       <span class="comment">/* Datapath ID. */</span></span><br><span class="line">    <span class="keyword">bool</span> forward_bpdu;          <span class="comment">/* Option to allow forwarding of BPDU frames</span></span><br><span class="line"><span class="comment">                                 * when NORMAL action is invoked. */</span></span><br><span class="line">    <span class="keyword">char</span> *mfr_desc;             <span class="comment">/* Manufacturer (NULL for default). */</span></span><br><span class="line">    <span class="keyword">char</span> *hw_desc;              <span class="comment">/* Hardware (NULL for default). */</span></span><br><span class="line">    <span class="keyword">char</span> *sw_desc;              <span class="comment">/* Software version (NULL for default). */</span></span><br><span class="line">    <span class="keyword">char</span> *serial_desc;          <span class="comment">/* Serial number (NULL for default). */</span></span><br><span class="line">    <span class="keyword">char</span> *dp_desc;              <span class="comment">/* Datapath description (NULL for default). */</span></span><br><span class="line">    <span class="keyword">enum</span> ofputil_frag_handling frag_handling;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Datapath. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hmap</span> <span class="title">ports</span>;</span>          <span class="comment">/* Contains "struct ofport"s. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">shash</span> <span class="title">port_by_name</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">simap</span> <span class="title">ofp_requests</span>;</span>  <span class="comment">/* OpenFlow port number requests. */</span></span><br><span class="line">    <span class="keyword">uint16_t</span> alloc_port_no;     <span class="comment">/* Last allocated OpenFlow port number. */</span></span><br><span class="line">    <span class="keyword">uint16_t</span> max_ports;         <span class="comment">/* Max possible OpenFlow port num, plus one. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hmap</span> <span class="title">ofport_usage</span>;</span>   <span class="comment">/* Map ofport to last used time. */</span></span><br><span class="line">    <span class="keyword">uint64_t</span> change_seq;        <span class="comment">/* Change sequence for netdev status. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Flow tables. */</span></span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> eviction_group_timer; <span class="comment">/* For rate limited reheapification. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">oftable</span> *<span class="title">tables</span>;</span></span><br><span class="line">    <span class="keyword">int</span> n_tables;</span><br><span class="line">    <span class="keyword">ovs_version_t</span> tables_version;  <span class="comment">/* Controls which rules are visible to</span></span><br><span class="line"><span class="comment">                                    * table lookups. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Rules indexed on their cookie values, in all flow tables. */</span></span><br><span class="line">    <span class="function">struct hindex cookies <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line">    <span class="function">struct hmap learned_cookies <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* List of expirable flows, in all flow tables. */</span></span><br><span class="line">    <span class="function">struct ovs_list expirable <span class="title">OVS_GUARDED_BY</span><span class="params">(ofproto_mutex)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Meter table.</span></span><br><span class="line"><span class="comment">     * OpenFlow meters start at 1.  To avoid confusion we leave the first</span></span><br><span class="line"><span class="comment">     * pointer in the array un-used, and index directly with the OpenFlow</span></span><br><span class="line"><span class="comment">     * meter_id. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ofputil_meter_features</span> <span class="title">meter_features</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">meter</span> **<span class="title">meters</span>;</span> <span class="comment">/* 'meter_features.max_meter' + 1 pointers. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* OpenFlow connections. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">connmgr</span> *<span class="title">connmgr</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> min_mtu;                    <span class="comment">/* Current MTU of non-internal ports. */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Groups. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">cmap</span> <span class="title">groups</span>;</span>               <span class="comment">/* Contains "struct ofgroup"s. */</span></span><br><span class="line">    <span class="keyword">uint32_t</span> n_groups[<span class="number">4</span>] OVS_GUARDED; <span class="comment">/* # of existing groups of each type. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ofputil_group_features</span> <span class="title">ogf</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Tunnel TLV mapping table. */</span></span><br><span class="line">    OVSRCU_TYPE(struct tun_table *) metadata_tab;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Variable length mf_field mapping. Stores all configured variable length</span></span><br><span class="line"><span class="comment">     * meta-flow fields (struct mf_field) in a switch. */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">vl_mff_map</span> <span class="title">vl_mff_map</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li>如果有超时时间的设置，调用<code>ovs_list_insert</code>将rule-&gt;expirable添加到<code>ofproto-&gt;expirable</code>中</li><li>调用<code>cookies_insert</code>将<code>rule-&gt;cookie_node</code>插入<code>ofproto-&gt;cookies</code></li><li><code>eviction_group_add_rule</code>先不管</li><li>如果有meter配置，调用<code>meter_insert_rule</code></li><li>有group的话，调用<code>ofproto_group_lookup</code>和<code>group_add_rule</code></li></ul><h1 id="EMC查找"><a href="#EMC查找" class="headerlink" title="EMC查找"></a>EMC查找</h1><hr><p>首先是报文接收，路径之前我们写过，<code>pmd_thread_main--&gt;dp_netdev_process_rxq_port--&gt;netdev_rxq_recv--&gt;netdev_dpdk_vhost_rxq_recv--&gt;dp_netdev_input--&gt;dp_netdev_input__</code>进行报文的处理。查找到就直接进行操作即可，如果查找不到的话就需要去dpcls进行查找了，找到后调用<code>emc_insert</code>安装EMC流表。</p><h2 id="key值提取"><a href="#key值提取" class="headerlink" title="key值提取"></a>key值提取</h2><p><code>emc_processing--&gt;miniflow_extract</code>会进行key值的提取。这块相对比较简单，我们就不看了，主要就是提取L2、L3、L4的报文协议头。</p><h2 id="emc-processing"><a href="#emc-processing" class="headerlink" title="emc_processing"></a><code>emc_processing</code></h2><ul><li>因为之前收取报文，一次最多NETDEV_MAX_BURST(32)个报文，所以是循环查表</li><li><code>miniflow_extract</code>主要是讲报文的信息提取到<code>key-&gt;mf</code></li><li><code>dpif_netdev_packet_get_rss_hash</code>是获取rss计算的hash值，如果没有计算，则调用<code>miniflow_hash_5tuple</code>计算出hash值</li><li><code>emc_lookup</code>主要是在pmd的flowcache中查找表项，必须是hash值、key-&gt;mf、并且流表是alive的</li><li>如果匹配，<code>dp_netdev_queue_batches</code>主要是将报文添加到批处理中</li><li>如果不匹配，记录下不匹配的报文</li><li>循环持续到处理完所有的报文</li><li><code>dp_netdev_count_packet</code>主要是统计一下丢弃的报文、不匹配的报文、和EMC匹配的报文数</li></ul><h1 id="dpcls查找"><a href="#dpcls查找" class="headerlink" title="dpcls查找"></a>dpcls查找</h1><hr><p>上面EMC查找匹配的报文会放在批处理里面，还会剩下不匹配的报文，接下来会在dpcls中查找。</p><h2 id="fast-path-processing"><a href="#fast-path-processing" class="headerlink" title="fast_path_processing"></a><code>fast_path_processing</code></h2><ul><li><code>dp_netdev_pmd_lookup_dpcls</code>根据报文入端口从pmd找出对应的classifier</li><li>如果找不到classifier，则记录为miss</li><li>如果找到则继续调用<code>dpcls_lookup</code>从各个子表找到合适的流表，只要有一个报文不匹配也记录为miss</li><li>如果都匹配则继续下面的操作，如果有不匹配的报文，尝试upcall的读锁</li><li>获取读锁失败，删掉不匹配的报文</li><li>获取读锁成功，则调用<code>dp_netdev_pmd_lookup_flow</code>重新查一下，以防意外收获，查找到了就继续</li><li>如果依然没有查询到，则调用<code>handle_packet_upcall</code>继续调用到ofproto classifier的流表查找。</li><li>接下来对报文检测已经匹配到流表的，调用<code>emc_insert</code>将流表插入EMC中</li><li>最后调用<code>dp_netdev_queue_batches</code>将报文加入批处理中</li><li>记录丢弃的报文、不匹配的报文、查找的报文和匹配掩码的报文</li></ul><p><code>dpcls_lookup</code>比较复杂，主要是根据不同的掩码进行子表的区分，然后拿着报文分别去所有的子表用key和mask计算出hash，查看子表中有没有相应的node，如果有的话查看是否有hash冲突链，最终查看是否有匹配key值的表项。我们直接看一下代码</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">bool</span></span><br><span class="line">dpcls_lookup(struct dpcls *cls, <span class="keyword">const</span> struct netdev_flow_key keys[],</span><br><span class="line">            struct dpcls_rule **rules, <span class="keyword">const</span> <span class="keyword">size_t</span> cnt,</span><br><span class="line">            <span class="keyword">int</span> *num_lookups_p)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">typedef</span> <span class="keyword">uint32_t</span> map_type;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAP_BITS (sizeof(map_type) * CHAR_BIT)</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">dpcls_subtable</span> *<span class="title">subtable</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//keys_map所有位都置1</span></span><br><span class="line">    map_type keys_map = TYPE_MAXIMUM(map_type); <span class="comment">/* Set all bits. */</span></span><br><span class="line">    map_type found_map;</span><br><span class="line">    <span class="keyword">uint32_t</span> hashes[MAP_BITS];</span><br><span class="line">    <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">cmap_node</span> *<span class="title">nodes</span>[<span class="title">MAP_BITS</span>];</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//清除多余的位，只记录跟报文一样多的位</span></span><br><span class="line">    <span class="keyword">if</span> (cnt != MAP_BITS) &#123;</span><br><span class="line">        keys_map &gt;&gt;= MAP_BITS - cnt; <span class="comment">/* Clear extra bits. */</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">memset</span>(rules, <span class="number">0</span>, cnt * <span class="keyword">sizeof</span> *rules);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> lookups_match = <span class="number">0</span>, subtable_pos = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//dpcls是由众多的subtables组成，当新的规则插入时，子表根据情况动态创建。</span></span><br><span class="line">    <span class="comment">//每个子表都是根据掩码来区分的，我们通过key和子表的掩码进行计算，</span></span><br><span class="line">    <span class="comment">//找到匹配的表项，因为不会重复，所以只要找到即可停止</span></span><br><span class="line">    <span class="comment">//以下就是循环所有子表进行查找</span></span><br><span class="line">    PVECTOR_FOR_EACH (subtable, &amp;cls-&gt;subtables) &#123;</span><br><span class="line">        <span class="keyword">int</span> i;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//这个循环是找到keys_map是1的最低位是多少，一开始的时候肯定全是1，就是从0开始</span></span><br><span class="line">        <span class="comment">//然后根据报文的key和mask计算出hash存储起来，继续下一个1的位</span></span><br><span class="line">        <span class="comment">//直到计算出所有报文hash值，下面会去匹配表项的</span></span><br><span class="line">        <span class="comment">//hash值的计算可以通过cpu加速，需要cpu支持，并且编译时配置"-msse4.2"</span></span><br><span class="line">        ULLONG_FOR_EACH_1(i, keys_map) &#123;</span><br><span class="line">            hashes[i] = netdev_flow_key_hash_in_mask(&amp;keys[i],</span><br><span class="line">                        &amp;subtable-&gt;mask);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//从子表中进行hash值的匹配，将匹配到node的报文的bit置1到found_map</span></span><br><span class="line">        found_map = cmap_find_batch(&amp;subtable-&gt;rules, keys_map, hashes, nodes);</span><br><span class="line">        <span class="comment">//在找到匹配node的报文的冲突hash链中继续详细匹配报文</span></span><br><span class="line">        ULLONG_FOR_EACH_1(i, found_map) &#123;</span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">dpcls_rule</span> *<span class="title">rule</span>;</span></span><br><span class="line">            <span class="comment">//冲突链中继续检测key值是否匹配</span></span><br><span class="line">            CMAP_NODE_FOR_EACH (rule, cmap_node, nodes[i]) &#123;</span><br><span class="line">                <span class="keyword">if</span> (OVS_LIKELY(dpcls_rule_matches_key(rule, &amp;keys[i]))) &#123;</span><br><span class="line">                    <span class="comment">//找到匹配的规则，则记录一下，后面会用到</span></span><br><span class="line">                    rules[i] = rule;</span><br><span class="line">                    subtable-&gt;hit_cnt++;</span><br><span class="line">                    lookups_match += subtable_pos;</span><br><span class="line">                    <span class="keyword">goto</span> next;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//不匹配则将该位设置为0</span></span><br><span class="line">            ULLONG_SET0(found_map, i);  <span class="comment">/* Did not match. */</span></span><br><span class="line">next:</span><br><span class="line">            ;                     <span class="comment">/* Keep Sparse happy. */</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//清除已经匹配流表的位</span></span><br><span class="line">        keys_map &amp;= ~found_map;             <span class="comment">/* Clear the found rules. */</span></span><br><span class="line">        <span class="keyword">if</span> (!keys_map) &#123;</span><br><span class="line">            <span class="keyword">if</span> (num_lookups_p) &#123;</span><br><span class="line">                *num_lookups_p = lookups_match;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;              <span class="comment">/* All found. */</span></span><br><span class="line">        &#125;</span><br><span class="line">        subtable_pos++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (num_lookups_p) &#123;</span><br><span class="line">        *num_lookups_p = lookups_match;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;                     <span class="comment">/* Some misses. */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="EMC流表安装"><a href="#EMC流表安装" class="headerlink" title="EMC流表安装"></a>EMC流表安装</h1><hr><p>dpcls会查找到rules，然后rules转换成flow，最后调用<code>emc_insert</code>将流表插入到EMC中。</p><h2 id="emc-insert"><a href="#emc-insert" class="headerlink" title="emc_insert"></a><code>emc_insert</code></h2><ul><li>根据key-&gt;hash找到hash桶，并且进行轮询</li><li>查看是否有匹配的key值，有的话调用<code>emc_change_entry</code>修改流表。</li><li>如果没有匹配的就会根据算法记录一个entry，用来替代</li><li>循环完毕之后，调用<code>emc_change_entry</code>替代之前不用的流表</li></ul><h2 id="emc-change-entry"><a href="#emc-change-entry" class="headerlink" title="emc_change_entry"></a><code>emc_change_entry</code></h2><p>操作很简单，就是赋值netdev_flow_key和dp_netdev_flow</p><h1 id="ofproto-classifier查找"><a href="#ofproto-classifier查找" class="headerlink" title="ofproto classifier查找"></a>ofproto classifier查找</h1><hr><h2 id="handle-packet-upcall"><a href="#handle-packet-upcall" class="headerlink" title="handle_packet_upcall"></a><code>handle_packet_upcall</code></h2><ul><li><code>miniflow_expand</code>讲key-&gt;mf解析到match.flow</li><li><code>dpif_flow_hash</code>根据key值计算出hash</li><li><code>dp_netdev_upcall</code>是进一步调用去ofproto classifier查表的接口，如果失败则删除报文</li><li><code>dp_netdev_execute_actions</code>可能是直接执行action，后期需要看看为什么不能放入批处理，现在还不明白</li><li><code>dp_netdev_pmd_lookup_flow</code>需要重新查找dpcls，没有查找到则调用<code>dp_netdev_flow_add</code>添加流表</li><li><code>emc_insert</code>讲dpcls的流表插入EMC中</li></ul><h2 id="dp-netdev-upcall-gt-upcall-cb"><a href="#dp-netdev-upcall-gt-upcall-cb" class="headerlink" title="dp_netdev_upcall--&gt;upcall_cb"></a><code>dp_netdev_upcall--&gt;upcall_cb</code></h2><ul><li><code>upcall_receive</code>主要是将一堆信息解析到upcall中</li><li><code>process_upcall</code>根据upcall的类型MISS_UPCALL确定调用函数<code>upcall_xlate</code></li></ul><h2 id="upcall-xlate"><a href="#upcall-xlate" class="headerlink" title="upcall_xlate"></a><code>upcall_xlate</code></h2><ul><li><code>xlate_in_init</code>主要是将upcall的数据转给xlate_in</li><li><code>xlate_actions</code>主要是进行流表查找</li></ul><h2 id="xlate-actions"><a href="#xlate-actions" class="headerlink" title="xlate_actions"></a><code>xlate_actions</code></h2><ul><li>调用<code>xbridge_lookup</code>查找对应的xbridge信息</li><li>根据当前掌握的一堆信息生成一个结构<code>xlate_ctx</code></li><li><code>xlate_wc_init</code>主要是初始化通配符的一些已知的项</li><li><code>rule_dpif_lookup_from_table</code>会查找指定table的流表，默认是table 0，用一个循环去遍历每一个table，然后知道找到匹配的rule</li><li><code>do_xlate_actions</code>主要是执行所有的action，轮询所有的action，并且根据具体的情况进行相应的操作。</li><li><code>tun_metadata_to_geneve_udpif_mask</code>给geneve封装metadata</li></ul><h2 id="rule-dpif-lookup-from-table"><a href="#rule-dpif-lookup-from-table" class="headerlink" title="rule_dpif_lookup_from_table"></a><code>rule_dpif_lookup_from_table</code></h2><ul><li>如果报文分片，默认是设置源目的端口都设置为0，其他情况下丢弃报文。</li><li>遍历所有的table，每次都会调用<code>rule_dpif_lookup_in_table</code>去查找rule，如果找到最终找到之后返回，找不到的话就会去下一个table找。</li><li>如果遍历完成都找不到，则返回miss_rule</li></ul><h2 id="do-xlate-actions"><a href="#do-xlate-actions" class="headerlink" title="do_xlate_actions"></a><code>do_xlate_actions</code></h2><ul><li>根据查找到的rule，遍历所有的action，支持的有OFPACT_OUTPUT、OFPACT_GROUP、OFPACT_CONTROLLER、OFPACT_ENQUEUE、OFPACT_SET_VLAN_VID、OFPACT_SET_VLAN_PCP、OFPACT_STRIP_VLAN、OFPACT_PUSH_VLAN、OFPACT_SET_ETH_SRC、OFPACT_SET_ETH_DST、OFPACT_SET_IPV4_SRC、OFPACT_SET_IPV4_DST、OFPACT_SET_IP_DSCP、OFPACT_SET_IP_ECN、OFPACT_SET_IP_TTL、OFPACT_SET_L4_SRC_PORT、OFPACT_SET_L4_DST_PORT、OFPACT_RESUBMIT、OFPACT_SET_TUNNEL、OFPACT_SET_QUEUE、OFPACT_POP_QUEUE、OFPACT_REG_MOVE、OFPACT_SET_FIELD、OFPACT_STACK_PUSH、OFPACT_STACK_POP、OFPACT_PUSH_MPLS、OFPACT_POP_MPLS、OFPACT_SET_MPLS_LABEL、OFPACT_SET_MPLS_TC、OFPACT_SET_MPLS_TTL、OFPACT_DEC_MPLS_TTL、OFPACT_DEC_TTL、OFPACT_NOTE、OFPACT_MULTIPATH、OFPACT_BUNDLE、OFPACT_OUTPUT_REG、OFPACT_OUTPUT_TRUNC、OFPACT_LEARN、OFPACT_CONJUNCTION、OFPACT_EXIT、OFPACT_UNROLL_XLATE、OFPACT_FIN_TIMEOUT、OFPACT_CLEAR_ACTIONS、OFPACT_WRITE_ACTIONS、OFPACT_WRITE_METADATA、OFPACT_METER、OFPACT_GOTO_TABLE、OFPACT_SAMPLE、OFPACT_CLONE、OFPACT_CT、OFPACT_CT_CLEAR、OFPACT_NAT、OFPACT_DEBUG_RECIRC，因为action太多，我们先介绍几个常用的</li><li><code>OFPACT_OUTPUT</code>，<code>xlate_output_action</code>会根据端口情况进行一些操作，这块不细看了</li><li><code>OFPACT_CONTROLLER</code>，<code>execute_controller_action</code>生成一个packet_in报文，然后发送</li><li><code>OFPACT_SET_ETH_SRC</code>、<code>OFPACT_SET_ETH_DST</code>、<code>OFPACT_SET_IPV4_SRC</code>、<code>OFPACT_SET_IPV4_DST</code>、<code>OFPACT_SET_IP_DSCP</code>、<code>OFPACT_SET_IP_ECN</code>、<code>OFPACT_SET_IP_TTL</code>、<code>OFPACT_SET_L4_SRC_PORT</code>、<code>OFPACT_SET_L4_DST_PORT</code>，修改源目的mac、IP以及DSCP、ECN、TTL和L4的源目的端口</li><li><code>OFPACT_RESUBMIT</code>，<code>xlate_ofpact_resubmit</code>会继续查找指定的table的流表</li><li><code>OFPACT_SET_TUNNEL</code>，设置tunnel id</li><li><code>OFPACT_CT</code>，<code>compose_conntrack_action</code>执行完ct的设置之后回调<code>do_xlate_actions</code>执行其他的action</li></ul><h2 id="rule-dpif-lookup-from-table-gt-rule-dpif-lookup-in-table-gt-classifier-lookup-gt-classifier-lookup"><a href="#rule-dpif-lookup-from-table-gt-rule-dpif-lookup-in-table-gt-classifier-lookup-gt-classifier-lookup" class="headerlink" title="rule_dpif_lookup_from_table--&gt;rule_dpif_lookup_in_table--&gt;classifier_lookup--&gt;classifier_lookup__"></a><code>rule_dpif_lookup_from_table--&gt;rule_dpif_lookup_in_table--&gt;classifier_lookup--&gt;classifier_lookup__</code></h2><ul><li>遍历所有子表，然后调用<code>find_match_wc</code>根据流表和掩码计算hash，然后进行对子表的各个rule进行匹配比较、</li><li>如果是严格匹配的话就直接返回，不是严格匹配的话还有一系列操作，暂时先不写了。</li></ul><h1 id="dpcls-流表安装"><a href="#dpcls-流表安装" class="headerlink" title="dpcls 流表安装"></a>dpcls 流表安装</h1><p><code>handle_packet_upcall--&gt;dp_netdev_flow_add--&gt;dpcls_insert</code>主要是根据掩码找到相应的子表，然后插入当前的流表</p></div><div></div><footer class="post-footer"><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/2017/03/04/SDN/OVN/2017-03-04-ovn-northd/" rel="next" title="OVN Northd服务工作"><i class="fa fa-chevron-left"></i> OVN Northd服务工作</a></div><div class="post-nav-prev post-nav-item"> <a href="/2017/03/11/SDN/OVN/2017-03-11-ovn-controller/" rel="prev" title="OVN controller工作">OVN controller工作<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-copyright"><p><span>注意:</span>所有文章非特别说明皆为原创。为保证信息与源同步，转载时请务必注明文章出处！谢谢合作 :-)</p><p> <span>原始链接:</span><a class="post-url" href="/2017/03/05/SDN/OVS/2017-03-05-flow-translate/" title="OpenvSwitch 流表转换">http://zhaozhanxu.com/2017/03/05/SDN/OVS/2017-03-05-flow-translate/</a><span class="copy-path" data-clipboard-text="原文: http://zhaozhanxu.com/2017/03/05/SDN/OVS/2017-03-05-flow-translate/　　作者: 赵占旭" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span><script src="/js/clipboard.min.js"></script><script>var clipboard=new Clipboard(".copy-path")</script></p><p> <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/cn" title="中国大陆 (CC BY-NC-SA 4.0 CN)" target="_blank">"署名-非商用-相同方式共享 4.0"</a> 转载请保留原文链接及作者。</p></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> Table of Contents</li><li class="sidebar-nav-overview" data-target="site-overview"> Overview</li></ul><section class="site-overview sidebar-panel"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <a href="/about"><img class="site-author-image" itemprop="image" src="/images/public/me.jpg" alt="赵占旭"><p class="site-author-name" itemprop="name">赵占旭</p><p class="site-description motion-element" itemprop="description"></p></a></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives"><span class="site-state-item-count">61</span> <span class="site-state-item-name">posts</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories"><span class="site-state-item-count">7</span> <span class="site-state-item-name">categories</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags"><span class="site-state-item-count">14</span> <span class="site-state-item-name">tags</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="mailto:zhaozhanxu@163.com" target="_blank" title="Mail"><i class="fa fa-fw fa-envelope"></i> Mail</a></span><span class="links-of-author-item"><a href="https://github.com/zhaozhanxu" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span><span class="links-of-author-item"><a href="https://www.linkedin.com/in/zhaozhanxu" target="_blank" title="LinkedIn"><i class="fa fa-fw fa-linkedin"></i> LinkedIn</a></span><span class="links-of-author-item"><a href="https://twitter.com/zhaozhanxu" target="_blank" title="Twitter"><i class="fa fa-fw fa-twitter"></i> Twitter</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="Wechat"><i class="fa fa-fw fa-wechat"></i> Wechat</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="QQ"><i class="fa fa-fw fa-qq"></i> QQ</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-inline"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-address-book"></i> 基情链接</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="http://blog.csdn.net/jqh9804" title="呆子辉" target="_blank">呆子辉</a></li></ul></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#主要流程"><span class="nav-number">1.</span><span class="nav-text"><a href="#&#x4E3B;&#x8981;&#x6D41;&#x7A0B;" class="headerlink" title="&#x4E3B;&#x8981;&#x6D41;&#x7A0B;"></a> &#x4E3B;&#x8981;&#x6D41;&#x7A0B;</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#边界点"><span class="nav-number">2.</span><span class="nav-text"><a href="#&#x8FB9;&#x754C;&#x70B9;" class="headerlink" title="&#x8FB9;&#x754C;&#x70B9;"></a> &#x8FB9;&#x754C;&#x70B9;</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#流表下发"><span class="nav-number">3.</span><span class="nav-text"><a href="#&#x6D41;&#x8868;&#x4E0B;&#x53D1;" class="headerlink" title="&#x6D41;&#x8868;&#x4E0B;&#x53D1;"></a> &#x6D41;&#x8868;&#x4E0B;&#x53D1;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#流表发送"><span class="nav-number">3.1.</span><span class="nav-text"><a href="#&#x6D41;&#x8868;&#x53D1;&#x9001;" class="headerlink" title="&#x6D41;&#x8868;&#x53D1;&#x9001;"></a> &#x6D41;&#x8868;&#x53D1;&#x9001;</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#流表接收"><span class="nav-number">3.2.</span><span class="nav-text"><a href="#&#x6D41;&#x8868;&#x63A5;&#x6536;" class="headerlink" title="&#x6D41;&#x8868;&#x63A5;&#x6536;"></a> &#x6D41;&#x8868;&#x63A5;&#x6536;</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#服务启动"><span class="nav-number">3.2.1.</span><span class="nav-text"><a href="#&#x670D;&#x52A1;&#x542F;&#x52A8;" class="headerlink" title="&#x670D;&#x52A1;&#x542F;&#x52A8;"></a> &#x670D;&#x52A1;&#x542F;&#x52A8;</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#handle-openflow-gt-handle-openflow"><span class="nav-number">3.2.1.1.</span><span class="nav-text"><a href="#handle-openflow-gt-handle-openflow" class="headerlink" title="handle_openflow--&gt;handle_openflow__"></a> <code>handle_openflow--&gt;handle_openflow__</code></span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#handle-flow-mod"><span class="nav-number">3.2.1.2.</span><span class="nav-text"><a href="#handle-flow-mod" class="headerlink" title="handle_flow_mod"></a> <code>handle_flow_mod</code></span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ofproto-flow-mod-init"><span class="nav-number">3.2.1.3.</span><span class="nav-text"><a href="#ofproto-flow-mod-init" class="headerlink" title="ofproto_flow_mod_init"></a> <code>ofproto_flow_mod_init</code></span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#rule创建"><span class="nav-number">3.2.1.3.1.</span><span class="nav-text"><a href="#rule&#x521B;&#x5EFA;" class="headerlink" title="rule&#x521B;&#x5EFA;"></a> <code>rule&#x521B;&#x5EFA;</code></span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#cls-rule-init"><span class="nav-number">3.2.1.3.1.1.</span><span class="nav-text"><a href="#cls-rule-init" class="headerlink" title="cls_rule_init"></a> <code>cls_rule_init</code></span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#ofproto-rule-create"><span class="nav-number">3.2.1.3.1.2.</span><span class="nav-text"><a href="#ofproto-rule-create" class="headerlink" title="ofproto_rule_create"></a> <code>ofproto_rule_create</code></span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#add-flow-start"><span class="nav-number">3.2.1.4.</span><span class="nav-text"><a href="#add-flow-start" class="headerlink" title="add_flow_start"></a> <code>add_flow_start</code></span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ofproto-rule-insert"><span class="nav-number">3.2.1.5.</span><span class="nav-text"><a href="#ofproto-rule-insert" class="headerlink" title="ofproto_rule_insert__"></a> <code>ofproto_rule_insert__</code></span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#EMC查找"><span class="nav-number">4.</span><span class="nav-text"><a href="#EMC&#x67E5;&#x627E;" class="headerlink" title="EMC&#x67E5;&#x627E;"></a> EMC&#x67E5;&#x627E;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#key值提取"><span class="nav-number">4.1.</span><span class="nav-text"><a href="#key&#x503C;&#x63D0;&#x53D6;" class="headerlink" title="key&#x503C;&#x63D0;&#x53D6;"></a> key&#x503C;&#x63D0;&#x53D6;</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#emc-processing"><span class="nav-number">4.2.</span><span class="nav-text"><a href="#emc-processing" class="headerlink" title="emc_processing"></a> <code>emc_processing</code></span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#dpcls查找"><span class="nav-number">5.</span><span class="nav-text"><a href="#dpcls&#x67E5;&#x627E;" class="headerlink" title="dpcls&#x67E5;&#x627E;"></a> dpcls&#x67E5;&#x627E;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#fast-path-processing"><span class="nav-number">5.1.</span><span class="nav-text"><a href="#fast-path-processing" class="headerlink" title="fast_path_processing"></a> <code>fast_path_processing</code></span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#EMC流表安装"><span class="nav-number">6.</span><span class="nav-text"><a href="#EMC&#x6D41;&#x8868;&#x5B89;&#x88C5;" class="headerlink" title="EMC&#x6D41;&#x8868;&#x5B89;&#x88C5;"></a> EMC&#x6D41;&#x8868;&#x5B89;&#x88C5;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#emc-insert"><span class="nav-number">6.1.</span><span class="nav-text"><a href="#emc-insert" class="headerlink" title="emc_insert"></a> <code>emc_insert</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#emc-change-entry"><span class="nav-number">6.2.</span><span class="nav-text"><a href="#emc-change-entry" class="headerlink" title="emc_change_entry"></a> <code>emc_change_entry</code></span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#ofproto-classifier查找"><span class="nav-number">7.</span><span class="nav-text"><a href="#ofproto-classifier&#x67E5;&#x627E;" class="headerlink" title="ofproto classifier&#x67E5;&#x627E;"></a> ofproto classifier&#x67E5;&#x627E;</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#handle-packet-upcall"><span class="nav-number">7.1.</span><span class="nav-text"><a href="#handle-packet-upcall" class="headerlink" title="handle_packet_upcall"></a> <code>handle_packet_upcall</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#dp-netdev-upcall-gt-upcall-cb"><span class="nav-number">7.2.</span><span class="nav-text"><a href="#dp-netdev-upcall-gt-upcall-cb" class="headerlink" title="dp_netdev_upcall--&gt;upcall_cb"></a> <code>dp_netdev_upcall--&gt;upcall_cb</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#upcall-xlate"><span class="nav-number">7.3.</span><span class="nav-text"><a href="#upcall-xlate" class="headerlink" title="upcall_xlate"></a> <code>upcall_xlate</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#xlate-actions"><span class="nav-number">7.4.</span><span class="nav-text"><a href="#xlate-actions" class="headerlink" title="xlate_actions"></a> <code>xlate_actions</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#rule-dpif-lookup-from-table"><span class="nav-number">7.5.</span><span class="nav-text"><a href="#rule-dpif-lookup-from-table" class="headerlink" title="rule_dpif_lookup_from_table"></a> <code>rule_dpif_lookup_from_table</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#do-xlate-actions"><span class="nav-number">7.6.</span><span class="nav-text"><a href="#do-xlate-actions" class="headerlink" title="do_xlate_actions"></a> <code>do_xlate_actions</code></span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#rule-dpif-lookup-from-table-gt-rule-dpif-lookup-in-table-gt-classifier-lookup-gt-classifier-lookup"><span class="nav-number">7.7.</span><span class="nav-text"><a href="#rule-dpif-lookup-from-table-gt-rule-dpif-lookup-in-table-gt-classifier-lookup-gt-classifier-lookup" class="headerlink" title="rule_dpif_lookup_from_table--&gt;rule_dpif_lookup_in_table--&gt;classifier_lookup--&gt;classifier_lookup__"></a> <code>rule_dpif_lookup_from_table--&gt;rule_dpif_lookup_in_table--&gt;classifier_lookup--&gt;classifier_lookup__</code></span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#dpcls-流表安装"><span class="nav-number">8.</span><span class="nav-text"><a href="#dpcls-&#x6D41;&#x8868;&#x5B89;&#x88C5;" class="headerlink" title="dpcls &#x6D41;&#x8868;&#x5B89;&#x88C5;"></a> dpcls &#x6D41;&#x8868;&#x5B89;&#x88C5;</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright"> &copy; 2016 - <span itemprop="copyrightYear">2017</span><span class="with-love"><i class="fa fa-heart"></i></span> <span class="author" itemprop="copyrightHolder">赵占旭</span></div><div class="powered-by"> Powered by <a class="theme-link" href="https://hexo.io">Hexo</a></div><div class="theme-info"> Theme - <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">NexT</a></div><div class="busuanzi-count"><script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script><span class="site-uv"><i class="fa fa-user"></i><span class="busuanzi-value" id="busuanzi_value_site_uv"></span></span><span class="site-pv"><i class="fa fa-eye"></i><span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script><script type="text/javascript">function proceedsearch(){$("body").append('<div class="popoverlay">').css("overflow","hidden"),$(".popup").toggle()}var isfetched=!1,search_path="search.xml";0==search_path.length&&(search_path="search.xml");var path="/"+search_path,searchFunc=function(e,t,a){"use strict";$.ajax({url:e,dataType:"xml",async:!0,success:function(e){isfetched=!0,$(".popup").detach().appendTo(".header-inner");var r=$("entry",e).map(function(){return{title:$("title",this).text(),content:$("content",this).text(),url:$("url",this).text()}}).get(),c=document.getElementById(t),n=document.getElementById(a);c.addEventListener("input",function(){var e=0,t='<ul class="search-result-list">',a=this.value.trim().toLowerCase().split(/[\s\-]+/);n.innerHTML="",this.value.trim().length>1&&r.forEach(function(r){var c=!1,n=r.title.trim().toLowerCase(),s=r.content.trim().replace(/<[^>]+>/g,"").toLowerCase(),o=decodeURIComponent(r.url),i=-1,l=-1,p=-1;if(""!=n&&a.forEach(function(e,t){i=n.indexOf(e),l=s.indexOf(e),(i>=0||l>=0)&&(c=!0,0==t&&(p=l))}),c){e+=1,t+="<li><a href='"+o+"' class='search-result-title'>"+n+"</a>";var h=r.content.trim().replace(/<[^>]+>/g,"");if(p>=0){var u=p-20,d=p+80;u<0&&(u=0),0==u&&(d=50),d>h.length&&(d=h.length);var f=h.substring(u,d);a.forEach(function(e){var t=new RegExp(e,"gi");f=f.replace(t,'<b class="search-keyword">'+e+"</b>")}),t+='<p class="search-result">'+f+"...</p>"}t+="</li>"}}),t+="</ul>",0==e&&(t='<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'),""==a&&(t='<div id="no-result"><i class="fa fa-search fa-5x" /></div>'),n.innerHTML=t}),proceedsearch()}})};$(".popup-trigger").click(function(e){e.stopPropagation(),0==isfetched?searchFunc(path,"local-search-input","local-search-result"):proceedsearch()}),$(".popup-btn-close").click(function(e){$(".popup").hide(),$(".popoverlay").remove(),$("body").css("overflow","")}),$(".popup").click(function(e){e.stopPropagation()})</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script></body></html>